<?php
/**
 *+------------------
 * Lflow
 *+------------------
 * Copyright (c) 2023~2030 gitee.com/liu_guan_qing All rights reserved.本版权不可删除，侵权必究
 *+------------------
 * Author: Mr.April(405784684@qq.com)
 *+------------------
 */
declare (strict_types=1);

namespace lflow\ckpt;

use lflow\assign\AssignmentHandler;
use lflow\core\Execution;
use lflow\handlers\impl\MergeActorHandler;
use lflow\lib\enum\TaskEnum;
use lflow\lib\util\AssertHelper;
use lflow\lib\util\ClassUtil;
use lflow\lib\util\StringHelper;

/**
 * 任务定义task元素
 *
 * @author Mr.April
 * @since  1.0
 */
class TaskCkpt extends WorkFlowCkpt
{
    /**
     * 类型：普通任务
     */
    const PERFORMTYPE_ANY = "ANY";
    /**
     * 类型：参与者fork任务
     */
    const PERFORMTYPE_ALL = "ALL";
    /**
     * 类型：主办任务
     */
    const TASKTYPE_MAJOR = "Major";
    /**
     * 类型：协办任务
     */
    const TASKTYPE_AIDANT = "Aidant";

    /**
     * 参与类型
     */
    public static array $PerformType = ['ANY', ' ALL'];

    /**
     * 任务类型(Major:主办的,Aidant:协助的,Record:仅仅作为记录的)
     */
    public static array $TaskType = ['Major', 'Aidant', 'Record',];

    /**
     * 参与方式
     * any：任何一个参与者处理完即执行下一步
     * all：所有参与者都完成，才可执行下一步
     */
    private string $performType = self::PERFORMTYPE_ANY;

    /**
     * 任务类型
     * major：主办任务
     * aidant：协办任务
     */
    private string $taskType = self::TASKTYPE_MAJOR;

    /**
     * @var string 参与者类型
     */
    private string $scope;

    /**
     * 参与者变量名称
     */
    private string $assignee;

    /**
     * 期望完成时间
     */
    private string $expireTime;

    /**
     * 提醒时间
     */
    private string $reminderTime;

    /**
     * 提醒间隔(分钟)
     */
    private string $reminderRepeat;

    /**
     * 是否自动执行
     */
    private string $autoExecute;

    /**
     * 任务执行后回调类
     */
    private string $callback;
    /**
     * 分配参与者处理类型
     */
    private string $assignmentHandler;

    /**
     * 任务执行后回调对象
     */
    private $callbackObject;

    /**
     * 分配参与者处理对象
     */
    private ?AssignmentHandler $assignmentHandlerObject;

    /**
     * 字段模型集合
     */
    private FieldCkpt $fields;

    public function exec(Execution $execution): void
    {
        if ($this->performType == null || StringHelper::equalsIgnoreCase(self::PERFORMTYPE_ANY, $this->performType)) {
            /**
             * any方式，直接执行输出变迁
             */
            $this->runOutTransition($execution);
        } else {
            /**
             * all方式，需要判断是否已全部合并
             * 由于all方式分配任务，是每人一个任务
             * 那么此时需要判断之前分配的所有任务都执行完成后，才可执行下一步，否则不处理
             */
            $this->fire(new MergeActorHandler($this->getName()), $execution);
            if ($execution->isMerged()) {
                $this->runOutTransition($execution);
            }
        }
    }

    public function isPerformAny(): bool
    {
        return StringHelper::equalsIgnoreCase(self::PERFORMTYPE_ANY, $this->performType);
    }

    public function isPerformAll(): bool
    {
        return StringHelper::equalsIgnoreCase(self::PERFORMTYPE_ALL, $this->performType);
    }

    public function isMajor(): bool
    {
        return StringHelper::equalsIgnoreCase(self::TASKTYPE_MAJOR, $this->taskType);
    }

    public function getScope(): string
    {
        return $this->scope ?? '';
    }

    public function setScope(string $scope): void
    {
        $this->scope = $scope;
    }

    public function getAssignee(): string
    {
        return $this->assignee;
    }

    public function setAssignee(string $assignee): void
    {
        $this->assignee = $assignee;
    }

    public function getExpireTime(): string
    {
        return $this->expireTime ?? '';
    }

    public function setExpireTime($expireTime): void
    {
        $this->expireTime = $expireTime;
    }

    public function getTaskType(): string
    {
        return $this->taskType;
    }

    public function setTaskType(string $taskType): void
    {
        $this->taskType = (StringHelper::isEmpty($taskType) ? self::TASKTYPE_MAJOR : $this->taskType);
    }

    public function getPerformType(): string
    {
        return $this->performType;
    }

    public function setPerformType(string $performType): void
    {
        $this->performType = (StringHelper:: isEmpty($performType) ? self::PERFORMTYPE_ANY : $performType);
    }

    public function getReminderTime(): string
    {
        return $this->reminderTime ?? '';
    }

    public function setReminderTime(string $reminderTime): void
    {
        $this->reminderTime = $reminderTime;
    }

    public function getReminderRepeat(): string
    {
        return $this->reminderRepeat;
    }

    public function setReminderRepeat(string $reminderRepeat): void
    {
        $this->reminderRepeat = $reminderRepeat;
    }

    public function getAutoExecute(): string
    {
        return $this->autoExecute;
    }

    public function setAutoExecute(string $autoExecute): void
    {
        $this->autoExecute = $autoExecute;
    }

    public function getAssignmentHandlerObject(): ?AssignmentHandler
    {
        return $this->assignmentHandlerObject ?? null;
    }

    public function setAssignmentHandler(string $assignmentHandlerStr): void
    {
        //通过类全路径实例化
        if (StringHelper::isNotEmpty($assignmentHandlerStr)) {
            $this->assignmentHandler = $assignmentHandlerStr;
            $assignmentHandlerObject = app()->make($assignmentHandlerStr);
            AssertHelper::notNull($assignmentHandlerObject, "分配参与者处理类实例化失败");
            $this->assignmentHandlerObject = $assignmentHandlerObject;
        }
    }

    public function getAssignmentHandler(): string
    {
        return $this->assignmentHandler;
    }

    public function getCallback(): string
    {
        return $this->callback;
    }

    public function getCallbackObject(): JobCallback
    {
        return $this->callbackObject;
    }

    //回调处理类写入
    public function setCallback(string|null $callbackStr)
    {
        if (StringHelper::isNotEmpty($callbackStr)) {
            $this->callback = $callbackStr;
            $callbackObject = ClassUtil::instantiateClass($callbackStr);
            AssertHelper::notNull($callbackObject, "回调处理类实例化失败");
            $this->callbackObject = $callbackObject;
        }
    }

    public function getFields(): array|object
    {
        return $this->fields;
    }

    public function setFields(array|object $fields)
    {
        $this->fields = $fields;
    }

    //模型集合
    public function getNextTaskCkpt(): array|object
    {
        $models = [];
        $temp   = [];
        foreach ($this->getOutputs() as $tm) {
            $this->addNextModels($models, $tm, TaskCkpt::class, $temp);
        }
        return $models;
    }
}
